/*     */ package com.zimbra.cs.session;
/*     */ 
/*     */ import com.zimbra.common.account.Key.AccountBy;
/*     */ import com.zimbra.common.localconfig.KnownKey;
/*     */ import com.zimbra.common.localconfig.LC;
/*     */ import com.zimbra.common.service.ServiceException;
/*     */ import com.zimbra.common.util.Log;
/*     */ import com.zimbra.common.util.Pair;
/*     */ import com.zimbra.common.util.ZimbraLog;
/*     */ import com.zimbra.cs.account.AccessManager;
/*     */ import com.zimbra.cs.account.Account;
/*     */ import com.zimbra.cs.account.Provisioning;
/*     */ import com.zimbra.cs.account.accesscontrol.AdminRight;
/*     */ import com.zimbra.cs.ldap.LdapUtil;
/*     */ import com.zimbra.cs.mailbox.MailItem.Type;
/*     */ import com.zimbra.cs.mailbox.MailServiceException;
/*     */ import com.zimbra.cs.mailbox.MailboxManager;
/*     */ import com.zimbra.cs.service.admin.AdminDocumentHandler;
/*     */ import com.zimbra.cs.util.Zimbra;
/*     */ import com.zimbra.soap.ZimbraSoapContext;
/*     */ import java.util.ArrayList;
/*     */ import java.util.Collection;
/*     */ import java.util.HashMap;
/*     */ import java.util.Iterator;
/*     */ import java.util.List;
/*     */ import java.util.Map;
/*     */ import java.util.Set;
/*     */ import java.util.Timer;
/*     */ import java.util.TimerTask;
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ public class WaitSetMgr
/*     */ {
/*     */   public static final String ALL_ACCOUNTS_ID_PREFIX = "AllWaitSet-";
/*  51 */   private static final int MAX_WAITSETS_PER_NONADMIN_ACCOUNT = LC.zimbra_waitset_max_per_account.intValueWithinRange(1, Integer.MAX_VALUE);
/*  52 */   private static final TimerTask sSweeper = new TimerTask() {
/*     */     public void run() {
/*     */       try {
/*     */         
/*     */       }
/*     */       catch (OutOfMemoryError e) {
/*  58 */         Zimbra.halt("out of memory", e);
/*     */       } catch (Throwable e) {
/*  60 */         if ((e instanceof OutOfMemoryError))
/*  61 */           Zimbra.halt("Caught out of memory error", e);
/*  62 */         ZimbraLog.session.warn("Caught exception in WaitSetMgr timer", e);
/*     */       }
/*     */     }
/*     */   };
/*     */   
/*  67 */   private static final HashMap<String, WaitSetBase> sWaitSets = new HashMap();
/*     */   
/*  69 */   private static final HashMap<String, List<String>> sWaitSetsByAccountId = new HashMap();
/*     */   
/*     */   private static final int WAITSET_SWEEP_DELAY = 60000;
/*     */   
/*  73 */   private static final int WAITSET_TIMEOUT = (int)(LC.zimbra_active_waitset_timeout_minutes.intValue() * 60000L);
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   public static Pair<String, List<WaitSetError>> create(String ownerAccountId, boolean allowMultiple, Set<MailItem.Type> defaultInterest, boolean allAccts, List<WaitSetAccount> add)
/*     */     throws ServiceException
/*     */   {
/*     */     String id;
/*     */     
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */     String id;
/*     */     
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*  95 */     if (allAccts)
/*     */     {
/*  97 */       id = "AllWaitSet-" + LdapUtil.generateUUID();
/*     */     } else {
/*  99 */       id = "WaitSet-" + LdapUtil.generateUUID();
/*     */     }
/*     */     
/*     */ 
/*     */ 
/* 104 */     List<WaitSetError> errors = null;
/* 105 */     WaitSetBase ws; if (allAccts) {
/* 106 */       AllAccountsWaitSet aws = AllAccountsWaitSet.create(ownerAccountId, id, defaultInterest);
/* 107 */       WaitSetBase ws = aws;
/* 108 */       errors = new ArrayList();
/*     */     } else {
/* 110 */       SomeAccountsWaitSet sws = new SomeAccountsWaitSet(ownerAccountId, id, defaultInterest);
/* 111 */       errors = sws.addAccounts(add);
/* 112 */       MailboxManager.getInstance().addListener(sws);
/* 113 */       ws = sws;
/*     */     }
/*     */     
/* 116 */     synchronized (sWaitSets) {
/* 117 */       if (!allowMultiple) {
/* 118 */         List<String> list = (List)sWaitSetsByAccountId.get(ownerAccountId);
/* 119 */         if ((list != null) && 
/* 120 */           (list.size() >= MAX_WAITSETS_PER_NONADMIN_ACCOUNT))
/*     */         {
/* 122 */           long oldestTime = Long.MAX_VALUE;
/* 123 */           String oldestId = null;
/* 124 */           for (String wsid : list) {
/* 125 */             WaitSetBase existingWs = lookupInternal(wsid);
/* 126 */             long time = existingWs.getLastAccessedTime();
/* 127 */             if (time < oldestTime) {
/* 128 */               oldestTime = time;
/* 129 */               oldestId = wsid;
/*     */             }
/*     */           }
/* 132 */           destroy(null, ownerAccountId, oldestId);
/*     */         }
/*     */       }
/*     */       
/*     */ 
/*     */ 
/* 138 */       ws.setLastAccessedTime(System.currentTimeMillis());
/* 139 */       sWaitSets.put(id, ws);
/* 140 */       List<String> list = (List)sWaitSetsByAccountId.get(ownerAccountId);
/* 141 */       if (list == null) {
/* 142 */         list = new ArrayList();
/* 143 */         sWaitSetsByAccountId.put(ownerAccountId, list);
/*     */       }
/* 145 */       list.add(id);
/*     */       
/*     */ 
/* 148 */       return new Pair(id, errors);
/*     */     }
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   public static void destroy(ZimbraSoapContext zsc, String requestingAcctId, String id)
/*     */     throws ServiceException
/*     */   {
/* 162 */     synchronized (sWaitSets) {
/* 163 */       WaitSetBase ws = lookupInternal(id);
/* 164 */       if (ws == null) {
/* 165 */         throw MailServiceException.NO_SUCH_WAITSET(id);
/*     */       }
/* 167 */       assert (!Thread.holdsLock(ws));
/*     */       
/*     */ 
/* 170 */       if (zsc != null) {
/* 171 */         if (id.startsWith("AllWaitSet-")) {
/* 172 */           checkRightForAllAccounts(zsc);
/*     */         } else {
/* 174 */           checkRightForOwnerAccount(ws, requestingAcctId);
/*     */         }
/*     */       }
/*     */       
/*     */ 
/* 179 */       List<String> list = (List)sWaitSetsByAccountId.get(ws.getOwnerAccountId());
/* 180 */       assert (list != null);
/* 181 */       list.remove(id);
/* 182 */       if (list.size() == 0) {
/* 183 */         sWaitSetsByAccountId.remove(ws.getOwnerAccountId());
/*     */       }
/*     */       
/*     */ 
/* 187 */       sWaitSets.remove(id);
/*     */       
/* 189 */       Map<String, WaitSetAccount> toCleanup = ws.destroy();
/* 190 */       if (toCleanup != null) {
/* 191 */         assert (!Thread.holdsLock(ws));
/* 192 */         for (WaitSetAccount wsa : toCleanup.values()) {
/* 193 */           wsa.cleanupSession();
/*     */         }
/*     */       }
/*     */     }
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   public static IWaitSet lookup(String id)
/*     */   {
/* 210 */     return lookupInternal(id);
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   public static IWaitSet lookupOrCreateForAllAccts(String ownerAccountId, String id, Set<MailItem.Type> defaultInterests, String lastKnownSeqNo)
/*     */     throws ServiceException
/*     */   {
/* 221 */     synchronized (sWaitSets) {
/* 222 */       if (!id.startsWith("AllWaitSet-")) {
/* 223 */         throw ServiceException.INVALID_REQUEST("Called WaitSetMgr.lookupOrCreate but wasn't an 'All-' waitset ID", null);
/*     */       }
/*     */       
/* 226 */       IWaitSet toRet = lookup(id);
/* 227 */       if (toRet == null)
/*     */       {
/* 229 */         AllAccountsWaitSet ws = AllAccountsWaitSet.createWithSeqNo(ownerAccountId, id, defaultInterests, lastKnownSeqNo);
/* 230 */         toRet = ws;
/* 231 */         ws.setLastAccessedTime(System.currentTimeMillis());
/*     */         
/*     */ 
/* 234 */         sWaitSets.put(id, ws);
/* 235 */         List<String> list = (List)sWaitSetsByAccountId.get(ownerAccountId);
/* 236 */         if (list == null) {
/* 237 */           list = new ArrayList();
/* 238 */           sWaitSetsByAccountId.put(ownerAccountId, list);
/*     */         }
/* 240 */         list.add(id);
/*     */       }
/*     */       
/* 243 */       assert ((toRet instanceof AllAccountsWaitSet));
/* 244 */       return toRet;
/*     */     }
/*     */   }
/*     */   
/*     */   public static void shutdown() {
/* 249 */     sSweeper.cancel();
/*     */   }
/*     */   
/*     */   public static void startup()
/*     */   {
/* 254 */     Zimbra.sTimer.schedule(sSweeper, 60000L, 60000L);
/*     */   }
/*     */   
/*     */   public static List<IWaitSet> getAll() {
/* 258 */     synchronized (sWaitSets) {
/* 259 */       List<IWaitSet> toRet = new ArrayList(sWaitSets.size());
/* 260 */       toRet.addAll(sWaitSets.values());
/* 261 */       return toRet;
/*     */     }
/*     */   }
/*     */   
/*     */   private static WaitSetBase lookupInternal(String id)
/*     */   {
/* 267 */     synchronized (sWaitSets) {
/* 268 */       WaitSetBase toRet = (WaitSetBase)sWaitSets.get(id);
/* 269 */       if (toRet != null) {
/* 270 */         assert (!Thread.holdsLock(toRet));
/* 271 */         synchronized (toRet) {
/* 272 */           toRet.setLastAccessedTime(System.currentTimeMillis());
/*     */         }
/*     */       }
/* 275 */       return toRet;
/*     */     }
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */   private static void sweep()
/*     */   {
/* 283 */     int activeSets = 0;
/* 284 */     int activeSessions = 0;
/* 285 */     int removed = 0;
/* 286 */     int withCallback = 0;
/* 287 */     long cutoffTime; Iterator<WaitSetBase> iter; synchronized (sWaitSets) {
/* 288 */       ZimbraLog.session.debug("active waitset timeout = %d ms", new Object[] { Integer.valueOf(WAITSET_TIMEOUT) });
/* 289 */       cutoffTime = System.currentTimeMillis() - WAITSET_TIMEOUT;
/*     */       
/* 291 */       for (iter = sWaitSets.values().iterator(); iter.hasNext();) {
/* 292 */         WaitSetBase ws = (WaitSetBase)iter.next();
/* 293 */         assert (!Thread.holdsLock(ws));
/*     */         
/* 295 */         Map<String, WaitSetAccount> toCleanup = null;
/*     */         
/* 297 */         synchronized (ws)
/*     */         {
/* 299 */           if ((ws.getCb() == null) && (ws.getLastAccessedTime() < cutoffTime))
/*     */           {
/* 301 */             List<String> list = (List)sWaitSetsByAccountId.get(ws.getOwnerAccountId());
/* 302 */             assert (list != null);
/* 303 */             list.remove(ws.getWaitSetId());
/* 304 */             if (list.size() == 0) {
/* 305 */               sWaitSetsByAccountId.remove(ws.getOwnerAccountId());
/*     */             }
/*     */             
/*     */ 
/* 309 */             iter.remove();
/* 310 */             toCleanup = ws.destroy();
/* 311 */             removed++;
/*     */           } else {
/* 313 */             if (ws.getCb() != null) {
/* 314 */               withCallback++;
/*     */             }
/* 316 */             activeSets++;
/* 317 */             activeSessions += ws.countSessions();
/*     */           }
/*     */         }
/*     */         
/*     */ 
/* 322 */         if (toCleanup != null) {
/* 323 */           assert (!Thread.holdsLock(ws));
/* 324 */           for (WaitSetAccount wsa : toCleanup.values()) {
/* 325 */             wsa.cleanupSession();
/*     */           }
/*     */         }
/*     */       }
/*     */     }
/* 330 */     if (removed > 0) {
/* 331 */       ZimbraLog.session.info("WaitSet sweeper timing out %d WaitSets due to inactivity", new Object[] { Integer.valueOf(removed) });
/*     */     }
/*     */     
/* 334 */     if (activeSets > 0) {
/* 335 */       ZimbraLog.session.info("WaitSet sweeper: %d active WaitSets (%d accounts) - %d sets with blocked callbacks", new Object[] { Integer.valueOf(activeSets), Integer.valueOf(activeSessions), Integer.valueOf(withCallback) });
/*     */     }
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */   public static void checkRightForAllAccounts(ZimbraSoapContext zsc)
/*     */     throws ServiceException
/*     */   {
/* 345 */     AdminDocumentHandler.checkRight(zsc, null, AdminRight.PR_SYSTEM_ADMIN_ONLY);
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */   public static void checkRightForAdditionalAccount(String acctId, ZimbraSoapContext zsc)
/*     */     throws ServiceException
/*     */   {
/* 354 */     Account acct = Provisioning.getInstance().get(Key.AccountBy.id, acctId);
/* 355 */     if (acct == null) {
/* 356 */       throw ServiceException.DEFEND_ACCOUNT_HARVEST(acctId);
/*     */     }
/* 358 */     if (!AccessManager.getInstance().canAccessAccount(zsc.getAuthToken(), acct, zsc.isUsingAdminPrivileges())) {
/* 359 */       throw ServiceException.PERM_DENIED("cannot access account " + acct.getName());
/*     */     }
/*     */   }
/*     */   
/*     */   public static void checkRightForOwnerAccount(IWaitSet ws, String requestingAcctId)
/*     */     throws ServiceException
/*     */   {
/* 366 */     if (!ws.getOwnerAccountId().equals(requestingAcctId)) {
/* 367 */       throw ServiceException.PERM_DENIED("Not owner(creator) of waitset");
/*     */     }
/*     */   }
/*     */ }


/* Location:              /home/mint/zimbrastore.jar!/com/zimbra/cs/session/WaitSetMgr.class
 * Java compiler version: 7 (51.0)
 * JD-Core Version:       0.7.1
 */